1 /** 2 Copyright: Copyright (c) 2018, Joakim Brännström. All rights reserved. 3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 */ 6 module code_checker.engine.builtin.clang_tidy_classification; 7 8 public import code_checker.engine.types : Severity; 9 10 @safe: 11 12 struct SeverityColor { 13 import colorize : Color, Background, Mode; 14 15 Color c = Color.white; 16 Background bg = Background.black; 17 Mode m; 18 } 19 20 immutable Severity[string] diagnosticSeverity; 21 immutable SeverityColor[Severity] severityColor; 22 23 shared static this() { 24 // copied from https://github.com/Ericsson/codechecker/blob/master/config/checker_severity_map.json 25 26 // sorted alphabetically 27 28 // dfmt off 29 diagnosticSeverity = [ 30 // these do not seem to exist. keeping if they are impl. in clang-tidy 31 "alpha.clone.CloneChecker": Severity.low, 32 "alpha.core.BoolAssignment": Severity.low, 33 "alpha.core.CallAndMessageUnInitRefArg": Severity.high, 34 "alpha.core.CastSize": Severity.low, 35 "alpha.core.CastToStruct": Severity.low, 36 "alpha.core.Conversion": Severity.low, 37 "alpha.core.FixedAddr": Severity.low, 38 "alpha.core.IdenticalExpr": Severity.low, 39 "alpha.core.PointerArithm": Severity.low, 40 "alpha.core.PointerSub": Severity.low, 41 "alpha.core.SizeofPtr": Severity.low, 42 "alpha.core.TestAfterDivZero": Severity.medium, 43 "alpha.cplusplus.DeleteWithNonVirtualDtor": Severity.high, 44 "alpha.cplusplus.IteratorRange": Severity.medium, 45 "alpha.cplusplus.MisusedMovedObject": Severity.medium, 46 "alpha.deadcode.UnreachableCode": Severity.low, 47 "alpha.osx.cocoa.DirectIvarAssignment": Severity.low, 48 "alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions": Severity.low, 49 "alpha.osx.cocoa.InstanceVariableInvalidation": Severity.low, 50 "alpha.osx.cocoa.MissingInvalidationMethod": Severity.low, 51 "alpha.osx.cocoa.localizability.PluralMisuseChecker": Severity.low, 52 "alpha.security.ArrayBound": Severity.high, 53 "alpha.security.ArrayBoundV2": Severity.high, 54 "alpha.security.MallocOverflow": Severity.high, 55 "alpha.security.ReturnPtrRange": Severity.low, 56 "alpha.unix.BlockInCriticalSection": Severity.low, 57 "alpha.unix.Chroot": Severity.medium, 58 "alpha.unix.PthreadLock": Severity.high, 59 "alpha.unix.SimpleStream": Severity.medium, 60 "alpha.unix.Stream": Severity.medium, 61 "alpha.unix.cstring.BufferOverlap": Severity.high, 62 "alpha.unix.cstring.NotNullTerminated": Severity.high, 63 "alpha.unix.cstring.OutOfBounds": Severity.high, 64 // --- 65 "android-cloexec-creat": Severity.medium, 66 "android-cloexec-fopen": Severity.medium, 67 "android-cloexec-open": Severity.medium, 68 "android-cloexec-socket": Severity.medium, 69 "boost-use-to-string": Severity.low, 70 "bugprone-argument-comment": Severity.low, 71 "bugprone-assert-side-effect": Severity.medium, 72 "bugprone-bool-pointer-implicit-conversion": Severity.low, 73 "bugprone-copy-constructor-init": Severity.medium, 74 "bugprone-dangling-handle": Severity.high, 75 "bugprone-fold-init-type": Severity.high, 76 "bugprone-forward-declaration-namespace": Severity.low, 77 "bugprone-inaccurate-erase": Severity.high, 78 "bugprone-integer-division": Severity.medium, 79 "bugprone-misplaced-operator-in-strlen-in-alloc": Severity.medium, 80 "bugprone-misplaced-operator-in-strlen-in-alloc": Severity.medium, 81 "bugprone-move-forwarding-reference": Severity.medium, 82 "bugprone-multiple-statement-macro": Severity.medium, 83 "bugprone-string-constructor": Severity.high, 84 "bugprone-suspicious-memset-usage": Severity.high, 85 "bugprone-undefined-memory-manipulation": Severity.medium, 86 "bugprone-use-after-move": Severity.high, 87 "bugprone-virtual-near-miss": Severity.medium, 88 "cert-dcl03-c": Severity.medium, 89 "cert-dcl21-cpp": Severity.low, 90 "cert-dcl50-cpp": Severity.low, 91 "cert-dcl54-cpp": Severity.medium, 92 "cert-dcl58-cpp": Severity.high, 93 "cert-dcl59-cpp": Severity.medium, 94 "cert-env33-c": Severity.medium, 95 "cert-err09-cpp": Severity.high, 96 "cert-err34-c": Severity.low, 97 "cert-err52-cpp": Severity.low, 98 "cert-err58-cpp": Severity.low, 99 "cert-err60-cpp": Severity.medium, 100 "cert-err61-cpp": Severity.high, 101 "cert-fio38-c": Severity.high, 102 "cert-flp30-c": Severity.high, 103 "cert-msc30-c": Severity.low, 104 "cert-msc50-cpp": Severity.low, 105 "cert-oop11-cpp": Severity.medium, 106 "clang-analyzer-core.CallAndMessage": Severity.high, 107 "clang-analyzer-core.DivideZero": Severity.high, 108 "clang-analyzer-core.DynamicTypePropagation": Severity.medium, 109 "clang-analyzer-core.NonNullParamChecker": Severity.high, 110 "clang-analyzer-core.NullDereference": Severity.high, 111 "clang-analyzer-core.StackAddressEscape": Severity.high, 112 "clang-analyzer-core.UndefinedBinaryOperatorResult": Severity.medium, 113 "clang-analyzer-core.VLASize": Severity.medium, 114 "clang-analyzer-core.builtin.BuiltinFunctions": Severity.medium, 115 "clang-analyzer-core.builtin.NoReturnFunctions": Severity.medium, 116 "clang-analyzer-core.uninitialized.ArraySubscript": Severity.medium, 117 "clang-analyzer-core.uninitialized.Assign": Severity.medium, 118 "clang-analyzer-core.uninitialized.Branch": Severity.medium, 119 "clang-analyzer-core.uninitialized.CapturedBlockVariable": Severity.medium, 120 "clang-analyzer-core.uninitialized.UndefReturn": Severity.high, 121 "clang-analyzer-cplusplus.NewDelete": Severity.high, 122 "clang-analyzer-cplusplus.NewDeleteLeaks": Severity.high, 123 "clang-analyzer-cplusplus.SelfAssignment": Severity.medium, 124 "clang-analyzer-deadcode.DeadStores": Severity.low, 125 "cppcoreguidelines-c-copy-assignment-signature": Severity.medium, 126 "cppcoreguidelines-interfaces-global-init": Severity.low, 127 "cppcoreguidelines-no-malloc": Severity.low, 128 "cppcoreguidelines-pro-bounds-array-to-pointer-decay": Severity.low, 129 "cppcoreguidelines-pro-bounds-constant-array-index": Severity.low, 130 "cppcoreguidelines-pro-bounds-pointer-arithmetic": Severity.low, 131 "cppcoreguidelines-pro-type-const-cast": Severity.low, 132 "cppcoreguidelines-pro-type-cstyle-cast": Severity.low, 133 "cppcoreguidelines-pro-type-member-init": Severity.low, 134 "cppcoreguidelines-pro-type-reinterpret-cast": Severity.low, 135 "cppcoreguidelines-pro-type-static-cast-downcast": Severity.low, 136 "cppcoreguidelines-pro-type-union-access": Severity.low, 137 "cppcoreguidelines-pro-type-vararg": Severity.low, 138 "cppcoreguidelines-slicing": Severity.low, 139 "cppcoreguidelines-special-member-functions": Severity.low, 140 "google-build-explicit-make-pair": Severity.medium, 141 "google-build-namespaces": Severity.medium, 142 "google-build-using-namespace": Severity.style, 143 "google-default-arguments": Severity.low, 144 "google-explicit-constructor": Severity.medium, 145 "google-global-names-in-headers": Severity.high, 146 "google-readability-braces-around-statements": Severity.style, 147 "google-readability-casting": Severity.low, 148 "google-readability-function-size": Severity.style, 149 "google-readability-namespace-comments": Severity.style, 150 "google-readability-redundant-smartptr-get": Severity.medium, 151 "google-readability-todo": Severity.style, 152 "google-runtime-int": Severity.low, 153 "google-runtime-member-string-references": Severity.low, 154 "google-runtime-memset": Severity.high, 155 "google-runtime-operator": Severity.medium, 156 "hicpp-braces-around-statements": Severity.style, 157 "hicpp-deprecated-headers": Severity.low, 158 "hicpp-exception-baseclass": Severity.low, 159 "hicpp-explicit-conversions": Severity.low, 160 "hicpp-function-size": Severity.low, 161 "hicpp-invalid-access-moved": Severity.high, 162 "hicpp-member-init": Severity.low, 163 "hicpp-move-const-arg": Severity.medium, 164 "hicpp-named-parameter": Severity.low, 165 "hicpp-new-delete-operators": Severity.low, 166 "hicpp-no-array-decay": Severity.low, 167 "hicpp-no-assembler": Severity.low, 168 "hicpp-no-malloc": Severity.low, 169 "hicpp-noexcept-move": Severity.medium, 170 "hicpp-signed-bitwise": Severity.low, 171 "hicpp-special-member-functions": Severity.low, 172 "hicpp-static-assert": Severity.low, 173 "hicpp-undelegated-constructor": Severity.medium, 174 "hicpp-use-auto": Severity.style, 175 "hicpp-use-emplace": Severity.style, 176 "hicpp-use-equals-default": Severity.low, 177 "hicpp-use-equals-delete": Severity.low, 178 "hicpp-use-noexcept": Severity.style, 179 "hicpp-use-nullptr": Severity.low, 180 "hicpp-use-override": Severity.low, 181 "hicpp-vararg": Severity.low, 182 "llvm-header-guard": Severity.low, 183 "llvm-include-order": Severity.low, 184 "llvm-namespace-comment": Severity.style, 185 "llvm-twine-local": Severity.low, 186 "clang-analyzer-llvm.Conventions": Severity.low, 187 "misc-argument-comment": Severity.low, 188 "misc-assert-side-effect": Severity.medium, 189 "misc-bool-pointer-implicit-conversion": Severity.low, 190 "misc-dangling-handle": Severity.high, 191 "misc-definitions-in-headers": Severity.medium, 192 "misc-fold-init-type": Severity.high, 193 "misc-forward-declaration-namespace": Severity.low, 194 "misc-forwarding-reference-overload": Severity.low, 195 "misc-inaccurate-erase": Severity.high, 196 "misc-incorrect-roundings": Severity.high, 197 "misc-inefficient-algorithm": Severity.medium, 198 "misc-lambda-function-name": Severity.low, 199 "misc-macro-parentheses": Severity.medium, 200 "misc-macro-repeated-side-effects": Severity.medium, 201 "misc-misplaced-const": Severity.low, 202 "misc-misplaced-widening-cast": Severity.high, 203 "misc-move-const-arg": Severity.medium, 204 "misc-move-constructor-init": Severity.medium, 205 "misc-move-forwarding-reference": Severity.medium, 206 "misc-multiple-statement-macro": Severity.medium, 207 "misc-new-delete-overloads": Severity.medium, 208 "misc-noexcept-move-constructor": Severity.medium, 209 "misc-non-copyable-objects": Severity.high, 210 "misc-redundant-expression": Severity.medium, 211 "misc-sizeof-container": Severity.high, 212 "misc-sizeof-expression": Severity.high, 213 "misc-static-assert": Severity.low, 214 "misc-string-compare": Severity.low, 215 "misc-string-constructor": Severity.high, 216 "misc-string-integer-assignment": Severity.low, 217 "misc-string-literal-with-embedded-nul": Severity.medium, 218 "misc-suspicious-enum-usage": Severity.high, 219 "misc-suspicious-missing-comma": Severity.high, 220 "misc-suspicious-semicolon": Severity.high, 221 "misc-suspicious-string-compare": Severity.medium, 222 "misc-swapped-arguments": Severity.high, 223 "misc-throw-by-value-catch-by-reference": Severity.high, 224 "misc-unconventional-assign-operator": Severity.medium, 225 "misc-undelegated-constructor": Severity.medium, 226 "misc-uniqueptr-reset-release": Severity.medium, 227 "misc-unused-alias-decls": Severity.low, 228 "misc-unused-parameters": Severity.low, 229 "misc-unused-raii": Severity.high, 230 "misc-unused-using-decls": Severity.low, 231 "misc-use-after-move": Severity.high, 232 "misc-virtual-near-miss": Severity.high, 233 "modernize-avoid-bind": Severity.style, 234 "modernize-deprecated-headers": Severity.low, 235 "modernize-loop-convert": Severity.style, 236 "modernize-make-shared": Severity.low, 237 "modernize-make-unique": Severity.low, 238 "modernize-pass-by-value": Severity.low, 239 "modernize-raw-string-literal": Severity.style, 240 "modernize-redundant-void-arg": Severity.style, 241 "modernize-replace-auto-ptr": Severity.low, 242 "modernize-replace-random-shuffle": Severity.low, 243 "modernize-return-braced-init-list": Severity.style, 244 "modernize-shrink-to-fit": Severity.style, 245 "modernize-unary-static-assert": Severity.style, 246 "modernize-use-auto": Severity.style, 247 "modernize-use-bool-literals": Severity.style, 248 "modernize-use-default-member-init": Severity.style, 249 "modernize-use-emplace": Severity.style, 250 "modernize-use-equals-default": Severity.style, 251 "modernize-use-equals-delete": Severity.style, 252 "modernize-use-noexcept": Severity.style, 253 "modernize-use-nullptr": Severity.low, 254 "modernize-use-override": Severity.low, 255 "modernize-use-transparent-functors": Severity.low, 256 "modernize-use-using": Severity.style, 257 "mpi-buffer-deref": Severity.low, 258 "mpi-type-mismatch": Severity.low, 259 "clang-analyzer-nullability.NullPassedToNonnull": Severity.high, 260 "clang-analyzer-nullability.NullReturnedFromNonnull": Severity.high, 261 "clang-analyzer-nullability.NullableDereferenced": Severity.medium, 262 "clang-analyzer-nullability.NullablePassedToNonnull": Severity.medium, 263 "clang-analyzer-nullability.NullableReturnedFromNonnull": Severity.medium, 264 "clang-analyzer-optin.cplusplus.VirtualCall": Severity.medium, 265 "clang-analyzer-optin.mpi.MPI-Checker": Severity.medium, 266 "clang-analyzer-optin.performance.Padding": Severity.low, 267 "clang-analyzer-optin.portability.UnixAPI": Severity.medium, 268 "performance-faster-string-find": Severity.low, 269 "performance-for-range-copy": Severity.low, 270 "performance-implicit-cast-in-loop": Severity.low, 271 "performance-implicit-conversion-in-loop": Severity.low, 272 "performance-inefficient-algorithm": Severity.medium, 273 "performance-inefficient-string-concatenation": Severity.low, 274 "performance-inefficient-vector-operation": Severity.low, 275 "performance-move-const-arg": Severity.medium, 276 "performance-move-constructor-init": Severity.medium, 277 "performance-noexcept-move-constructor": Severity.medium, 278 "performance-type-promotion-in-math-fn": Severity.low, 279 "performance-unnecessary-copy-initialization": Severity.low, 280 "performance-unnecessary-value-param": Severity.low, 281 "readability-avoid-const-params-in-decls": Severity.style, 282 "readability-braces-around-statements": Severity.style, 283 "readability-container-size-empty": Severity.style, 284 "readability-delete-null-pointer": Severity.style, 285 "readability-deleted-default": Severity.style, 286 "readability-else-after-return": Severity.style, 287 "readability-function-size": Severity.style, 288 "readability-identifier-naming": Severity.style, 289 "readability-implicit-bool-cast": Severity.style, 290 "readability-implicit-bool-conversion": Severity.style, 291 "readability-inconsistent-declaration-parameter-name": Severity.style, 292 "readability-misleading-indentation": Severity.low, 293 "readability-misplaced-array-index": Severity.style, 294 "readability-named-parameter": Severity.style, 295 "readability-non-const-parameter": Severity.style, 296 "readability-redundant-control-flow": Severity.style, 297 "readability-redundant-declaration": Severity.style, 298 "readability-redundant-function-ptr-dereference": Severity.style, 299 "readability-redundant-member-init": Severity.style, 300 "readability-redundant-smartptr-get": Severity.style, 301 "readability-redundant-string-cstr": Severity.style, 302 "readability-redundant-string-init": Severity.style, 303 "readability-simplify-boolean-expr": Severity.medium, 304 "readability-static-accessed-through-instance": Severity.style, 305 "readability-static-definition-in-anonymous-namespace": Severity.style, 306 "readability-uniqueptr-delete-release": Severity.style, 307 "clang-analyzer-security.FloatLoopCounter": Severity.medium, 308 "clang-analyzer-security.insecureAPI.UncheckedReturn": Severity.medium, 309 "clang-analyzer-security.insecureAPI.getpw": Severity.medium, 310 "clang-analyzer-security.insecureAPI.gets": Severity.medium, 311 "clang-analyzer-security.insecureAPI.mkstemp": Severity.medium, 312 "clang-analyzer-security.insecureAPI.mktemp": Severity.medium, 313 "clang-analyzer-security.insecureAPI.rand": Severity.medium, 314 "clang-analyzer-security.insecureAPI.strcpy": Severity.medium, 315 "clang-analyzer-security.insecureAPI.vfork": Severity.medium, 316 "clang-analyzer-unix.API": Severity.medium, 317 "clang-analyzer-unix.Malloc": Severity.medium, 318 "clang-analyzer-unix.MallocSizeof": Severity.medium, 319 "clang-analyzer-unix.MismatchedDeallocator": Severity.medium, 320 "clang-analyzer-unix.Vfork": Severity.medium, 321 "clang-analyzer-unix.cstring.BadSizeArg": Severity.medium, 322 "clang-analyzer-unix.cstring.NullArg": Severity.medium, 323 "clang-analyzer-valist.CopyToSelf": Severity.medium, 324 "clang-analyzer-valist.Uninitialized": Severity.medium, 325 "clang-analyzer-valist.Unterminated": Severity.medium, 326 ]; 327 328 import colorize : Color, Background, Mode; 329 330 severityColor = [ 331 Severity.style: SeverityColor(Color.light_cyan, Background.black, Mode.init_), 332 Severity.low: SeverityColor(Color.light_blue, Background.black, Mode.bold), 333 Severity.medium: SeverityColor(Color.light_yellow, Background.black, Mode.init_), 334 Severity.high: SeverityColor(Color.red, Background.black, Mode.bold), 335 Severity.critical: SeverityColor(Color.magenta, Background.black, Mode.bold), 336 ]; 337 // dfmt on 338 } 339 340 struct CountErrorsResult { 341 import code_checker.engine.types : Severity; 342 343 private { 344 int total; 345 int[Severity] score_; 346 } 347 348 /// Returns: the score when summing up the found occurancies. 349 int score() @safe pure nothrow const @nogc scope { 350 int sum; 351 // just chose some numbers. The intent is that warnings should be a high penalty 352 foreach (kv; score_.byKeyValue) { 353 final switch (kv.key) { 354 case Severity.style: 355 sum -= kv.value; 356 break; 357 case Severity.low: 358 sum -= kv.value * 2; 359 break; 360 case Severity.medium: 361 sum -= kv.value * 5; 362 break; 363 case Severity.high: 364 sum -= kv.value * 10; 365 break; 366 case Severity.critical: 367 sum -= kv.value * 100; 368 break; 369 } 370 } 371 372 return sum; 373 } 374 375 void put(const Severity s) { 376 total++; 377 378 if (auto v = s in score_) 379 (*v)++; 380 else 381 score_[s] = 1; 382 } 383 384 auto toRange() const { 385 import std.algorithm : map, sort; 386 import std.array : array; 387 import std.format : format; 388 389 return score_.byKeyValue.array.sort!((a, b) => a.key > b.key) 390 .map!(a => format("%s %s", a.value, a.key)); 391 } 392 } 393 394 @("shall sort the error counts") 395 unittest { 396 import std.traits : EnumMembers; 397 import code_checker.engine.types : Severity; 398 import unit_threaded; 399 400 CountErrorsResult r; 401 foreach (s; [EnumMembers!Severity]) 402 r.put(s); 403 404 r.toRange.shouldEqual(["1 critical", "1 high", "1 medium", "1 low", "1 style"]); 405 } 406 407 /** Apply `fn` on the diagnostic messages. 408 * 409 * The return value from fn replaces the message. This makes it possible to 410 * rewrite a message if needed. 411 * 412 * Params: 413 * diagFn = mapped onto a diagnostic message 414 * lines = an input range of lines to analyze for diagnostic messages 415 * w = output range that the resulting log is written to. 416 */ 417 void mapClangTidy(alias diagFn, Writer)(string[] lines, ref scope Writer w) { 418 import std.algorithm : startsWith; 419 import std.regex : ctRegex, matchFirst; 420 import std..string : startsWith; 421 import std.range : put; 422 423 auto re_error = ctRegex!(`.*:\d*:.*error:.*\[(.*)\]`); 424 425 foreach (l; lines) { 426 auto m = matchFirst(l, re_error); 427 428 if (m.length > 1) { 429 const s = classify(m[1]); 430 put(w, diagFn(s, l)); 431 } else { 432 put(w, l); 433 } 434 } 435 } 436 437 /// Returns: the classification of the diagnostic message. 438 Severity classify(string diagnostic_msg) { 439 import std..string : startsWith; 440 441 if (auto v = diagnostic_msg in diagnosticSeverity) { 442 return *v; 443 } 444 445 // this is a fallback when new rules are added to clang-tidy but 446 // they haven't been thoroughly analyzed in 447 // `code_checker.engine.builtin.clang_tidy_classification`. 448 if (diagnostic_msg.startsWith("readability-")) 449 return Severity.style; 450 else if (diagnostic_msg.startsWith("clang-analyzer-")) 451 return Severity.high; 452 453 return Severity.medium; 454 } 455 456 /** 457 * Params: 458 * predicate = param is the classification of the diagnostic message. True means that it is kept, false thrown away 459 * Returns: a range of rules to inactivate that are below `s` 460 */ 461 auto filterSeverity(alias predicate)() { 462 import std.algorithm : filter, map; 463 464 // dfmt off 465 return diagnosticSeverity 466 .byKeyValue 467 .filter!(a => predicate(a.value)) 468 .map!(a => a.key); 469 // dfmt on 470 } 471 472 /// Returns: severity as a string with colors. 473 string color(Severity s) { 474 import std.conv : to; 475 static import colorize; 476 477 SeverityColor sc; 478 479 if (auto v = s in severityColor) { 480 sc = *v; 481 } 482 483 return colorize.color(s.to!string, sc.c, sc.bg, sc.m); 484 }